package com.itheima.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.reggie.common.R;
import com.itheima.reggie.dto.DishDto;
import com.itheima.reggie.entity.Category;
import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.entity.DishFlavor;
import com.itheima.reggie.service.CategoryService;
import com.itheima.reggie.service.DishFlavorService;
import com.itheima.reggie.service.DishService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

/**
 * @author ：石破天
 * @date ：Created in 2022年05月26日
 * @description ：
 *   完成菜品相关的控制
 * @version: 1.0
 */
@RestController
@Slf4j
@RequestMapping("/dish")
@Api(tags = "菜品管理模块")
public class DishController {

    @Autowired
    private RedisTemplate redisTemplate;

    //  如果 拿菜品类型 直接接收  少了 菜品口味信息
    @Autowired
    private DishService dishService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private DishFlavorService dishFlavorService;
    /**
     *
     * @param dishDto  专门接收前端数据的
     * @return
     */
    @PostMapping
    @ApiOperation("新增菜品接口")
    public R<String> save(@RequestBody DishDto dishDto){
        log.info("dishDto:{}",dishDto);

        // dishDto的数据需要往几个表里面加
        // 往两个表 加数据是不是属于业务操作
        dishService.saveDishAndFlavor(dishDto);
        // 业务是不是需要保存一个菜品 和多个口味
       // 保存成功 说明redis不是最新数据了  根据categoryid 删除对应的键
        String key = "dish_"+dishDto.getCategoryId();
        redisTemplate.delete(key);//删除指定key
        return R.success("新增菜品成功");
    }

    /**
     *  菜品分页信息查询
     */
    @GetMapping("/page")
    @ApiOperation("菜品分页查询接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page",value = "页码",required = true),
            @ApiImplicitParam(name = "pageSize",value = "每页记录数",required = true),
            @ApiImplicitParam(name = "name",value = "菜品名称",required = false)
    }
    )
    public R<Page> page(int page,int pageSize,String name){
      log.info("[菜品分页操作],{},{},{}",page,pageSize,name);
      /*
        分页查询套路
           构建 分页构造器
           构建 条件构造器
           调用page方法
       */
      //构建page对象
        Page<Dish> pageInfo = new Page(page,pageSize);
        //根据条件 构建条件构造器
        LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();
        //首先 是不是 name的模糊查询
        wrapper.like(StringUtils.isNotEmpty(name),Dish::getName,name);
        // 如果还想要按照 更新日期倒序
        wrapper.orderByDesc(Dish::getUpdateTime);//日期倒序
        //执行page方法
        dishService.page(pageInfo,wrapper);

        // 查询到的 菜品数据里面是没有  菜品分类名称的
        // 前端看不到 菜品分类名称 原因就是 Dish类中 不包含 菜品分类名称
        // Dish类要跟 表 对应
        // DishDto里面加   它不需要跟表对象 ,前端缺啥数据 我补啥
        // 应该 把  Page<Dish> pageInfo === Page<DishDto> dishDtopage
        Page<DishDto> dishDtoPage = new Page<>();
        // 这个对象啥也没有   需要把 Page<Dish> pageInfo  原有的属性数据
                                // 给  Page<DishDto> dishDtopage
       // 老师交给大家一个好玩的  可以完成 对象属性的复制
//        BeanUtils.copyProperties(pageInfo,dishDtoPage);
//        // 直接 这样做 是有什么属性 复制什么属性
//                               // 把 pageInfo 对应的属性值
//                             //    复制 给 dishDtoPage 的属性
        //是page上所有属性都要复制过去吗?
        // 是不是在页面中显示的数据 是要 进行 变化的!!!
        // pageInfo  records属性 List<Dish>
        // dishDtoPage  records属性 List<DishDto>
        // 分页信息复制的时候要排除
        BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");
        // dishDtoPage 除了 records 其他属性都搞定
        List<DishDto> records  = new ArrayList<>();
        // 当前页显示的数据   records 里面啥都没有   这里面数据需要从哪里来?
        //  records  DishDto  ==Dish里面有的属性 DishDto都有
        List<Dish> dishRecords = pageInfo.getRecords();
        //        菜品的基本分页数据
        // 是不是应该 遍历 菜品分页基本数据 把基本数据转换成 DishDto 存到  records里面
        //  遍历拿到每个 Dish基本菜品数据    把Dish--DishDto 菜品扩展数据
        //     DishDto 还可以在添加 分类名称字段  DishDto封装好了 存到  records 集合
        for (Dish dish : dishRecords) {
            // 拿到了当前页查询到的每一个 基本菜品数据 dish  ==>没有菜品分类名称
            // DishDto 扩展菜品数据 包含了 基本菜品数据的所有属性
            DishDto dishDto = new DishDto();//dishDto是不是还没都属性
            // 应该把 dish所有属性  给 dishDto
            BeanUtils.copyProperties(dish,dishDto);// dishDto 你有的我都有
            // 你没有的我也能有
            //  这里的 分类名称 是不是应给根据 categoryId进行查询

            Category category = categoryService.getById(dish.getCategoryId());
            dishDto.setCategoryName(category.getName());
            // 还得把 这个升级了的菜品数据 放到当前页list中
            records.add(dishDto);
        }

        dishDtoPage.setRecords(records);
        return R.success(dishDtoPage);

    }

    /**
     * 根据菜品id查询菜品信息
     *    请求路径 /dish/15755675687898
     *      按照以前的 直接返回 dish数据 是不够的
     *      单独进行单表的查询还合适吗?
     *         dish查菜品口味信息  就是因为没有菜品口味信息才导致
     *            无法正常回显
     *        dish不能加,没关系  dish的子类 dishDto加了
     *
     */
    @ApiOperation("获取指定菜品接口")
    @GetMapping("/{id}")
    public R<DishDto> getById(@PathVariable Long id){
        log.info("[查询的id是:]"+id);
        // 因为没有对应dishDto表  我们需要定制这个查询方法
         ///  就不能用mp提供的方法直接使用了
                        //  作用 在组装 dishDto
        DishDto dishDto = dishService.getByIdWithFlavor(id);

        return R.success(dishDto);
    }

    /**
     * 根据id 更新菜品信息 以及 菜品口味信息
     *    请求参数写谁合适?
     *       怎么确定
     *         一看  包含dish基本信息+口味信息
     *         二选   DishDto
     */
    @PutMapping
    public R<String> update(@RequestBody DishDto dishDto){
        log.info("[根据id 更新菜品],dishDto:{}",dishDto);
        // dishService有没有方法 可以把 菜品信息和口味信息同时更新的?
        // 木有 因为mp提供的是单表  需要我们"寄几个"来完善
        dishService.updateWithFlavor(dishDto);
        // 更新成功 说明redis不是最新数据了  根据categoryid 删除对应的键
        String key = "dish_"+dishDto.getCategoryId();
        redisTemplate.delete(key);//删除指定ke
        return R.success("更新菜品及菜品口味成功");
    }

    /**
     * 根据条件查询对应的菜品数据
     *       根据 分类id
     *       分类id 数据 dish一个条件
     *       根据啥查 都能帮你 只要你是 dish一个条件
     *    格局打开了.....来者不拒
     */
    @GetMapping("/list")
    public R<List<DishDto>> list(Dish dish){

        //定义一个用于接收 该分类下菜品 集合的对象
        List<DishDto> redisDtoList = null;
        // 先去 redis 中 找一下 有没有 该分类下的 菜品清单
        //  redis存储 规律是  dish_categoryId
                            // dish_categoryId_1
        //从 redis中去读取
        String key = "dish_"+dish.getCategoryId();
        redisDtoList = (List<DishDto>) redisTemplate.opsForValue().get(key);
       log.info("从redis中读取的集合数据:"+redisDtoList);
       if(redisDtoList!=null){// 缓存中有该分类数据
           log.info("我们的数据是从redis中获取的 没有查询数据库...");
           return R.success(redisDtoList);
       }



        //构建查询条件
        LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();
        //加条件
        wrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());
       // 套餐里面加停售的还是启售的   启售的  status 是1 的
        wrapper.eq(Dish::getStatus,1);
        //你想排就排  --- 有排序字段  没有就按照 更新日期倒序
         wrapper.orderByDesc(Dish::getUpdateTime);
        List<Dish> list = dishService.list(wrapper);

        // 返回 List<DishDto>
        //  把 每一个dish---DishDto  dishDto 根据 菜品id查询到 对应的 口味信息
                                   //封装到 sishDto的 flavors  属性中
      List<DishDto>  dishDtoList = new ArrayList<>();
        for (Dish dish1 : list) {
            DishDto dishDto = new DishDto();
            BeanUtils.copyProperties(dish1,dishDto);
            // 根据拿到的 dishid 去查询相关的  口味信息
            Long dishId = dish1.getId();
            LambdaQueryWrapper<DishFlavor> wrapper1 = new LambdaQueryWrapper<>();
            wrapper1.eq(DishFlavor::getDishId,dishId);
            List<DishFlavor> flavors = dishFlavorService.list(wrapper1);
            dishDto.setFlavors(flavors);
            Category category = categoryService.getById(dish.getCategoryId());
            dishDto.setCategoryName(category.getName());

            dishDtoList.add(dishDto);
        }
          // 如果 redis没数据 就会继续往下执行 也就是执行mp中的sql语句
         // dishDtoList 是 mp查询到的数据  把它放到缓存中
        redisTemplate.opsForValue().set(key,dishDtoList);// 过期时间可设置 可以不用设置
       return R.success(dishDtoList);
    }

}
